package org.hawk.gwt.ppc.reflect.lang;

import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import junit.framework.TestCase;

import org.hawk.gwt.ppc.reflect.emul.java.lang.reflect.Method;
import org.hawk.gwt.ppc.reflect.lang.mock.Mock3;

public class MethodTestCase extends TestCase {
	protected void setUp() throws Exception {
		ReflectionTestHelper.initialize();
	}
	
	private ClassDelegate<Mock3> getMock(){
		return ClassDelegate.forClass(Mock3.class);
	}
	
	public void testGetMethods(){
		assertEquals(7,getMock().getMethods().length);
		Set<String> names = new HashSet<String>();
		for(Method m : getMock().getMethods()){
			assertTrue(Modifier.isPublic(m.getModifiers()));
			names.add(m.getName());
		}
		assertTrue(names.contains("getIntValue"));
		assertTrue(names.contains("getParent"));
		assertTrue(names.contains("getName"));
		assertTrue(names.contains("getClass"));
		assertTrue(names.contains("equals"));
		assertTrue(names.contains("hashCode"));
		assertTrue(names.contains("toString"));
	}
	
	public void testGetMethod() throws Exception {
		Method m = getMock().getMethod("getIntValue", 
				String.class,int.class);
		assertTrue(Modifier.isPublic(m.getModifiers()));
		assertEquals("getIntValue", m.getName());
		assertTrue(Arrays.equals(m.getParameterTypes(), new Class[]{
			String.class, int.class}));
		assertEquals(int.class, m.getReturnType());
		try{
			getMock().getMethod("unknown");
			fail();
		}
		catch(NoSuchMethodException ex){}
		try{
			getMock().getMethod("");
			fail();
		}
		catch(NoSuchMethodException ex){}
		try{
			getMock().getMethod("doSomething");
			fail();
		}
		catch(NoSuchMethodException ex){}
		try{
			getMock().getMethod(null);
			fail();
		}
		catch(NullPointerException ex){}
	}
	
	public void testGetDeclaredMethods(){
		assertEquals(5, getMock().getDeclaredMethods().length);
		Set<String> names = new HashSet<String>();
		for(Method m : getMock().getDeclaredMethods()){
			names.add(m.getName());
		}
		assertTrue(names.contains("getIntValue"));
		assertTrue(names.contains("getName"));
		assertTrue(names.contains("getParent"));
		assertTrue(names.contains("doSomething"));
		assertEquals(4,names.size());
	}
	
	public void testGetDeclaredMethod() throws Exception {
		Method m = getMock().getDeclaredMethod("doSomething");
		assertTrue(Modifier.isProtected(m.getModifiers()));
		assertEquals("doSomething", m.getName());
		assertEquals(0,m.getParameterTypes().length);
		assertEquals(Void.TYPE,m.getReturnType());
		try{
			getMock().getDeclaredMethod("unknown");
			fail();
		}
		catch(NoSuchMethodException ex){}
		try{
			getMock().getDeclaredMethod("");
			fail();
		}
		catch(NoSuchMethodException ex){}
		getMock().getDeclaredMethod("doSomething");
		try{
			getMock().getDeclaredMethod(null);
			fail();
		}
		catch(NullPointerException ex){}
	}
	
	public void testInvoke() throws Exception {
		Method m = getMock().getMethod("getIntValue", 
				String.class,int.class);
		Mock3 obj = new Mock3();
		assertEquals(5,m.invoke(obj, "",5));
		m = getMock().getDeclaredMethod("doSomething");
		try{
			m.invoke(obj);
			fail();
		}
		catch(IllegalAccessException ex){}
		m.setAccessible(true);
		m.invoke(obj);
	}
}
